/**
 * 1、Promise是一个构造函数，新建后立即执行，构造函数接收一个函数(执行器)作为参数
 * 2、这个函数（执行器）有两个函数作为参数参数，这两个参数的作用是改变Promise的状态，promise有三种状态，分别是等待（pending），成功（fulfilled）,失败（rejected）。
 *   resolve函数的作用：将状态从 pending-> fulfilled，并将成功之后的值传递出去
 *   rejected函数的作用：将状态从pending-> rejected，并将失败之后的原因传递出去
 *   一旦状态确定就不可更改
 * 3、then方法（里面有两个参数，第一参数成功的回调函数，第二参数（可选）失败的回调函数）
 *      作用：判断promise的状态，如果状态为成功（fulfilled）调用成功的回调函数(并将成功的值传递进去)，如果状态是失败调用失败的回调函数（并将失败的原因传递进去）
 *      异步逻辑：执行then的时候，如果状态为等待（pending）,我们将成功的回调和失败的回调存储起来，当调用resolve的时候即状态从等待变成成功时在调用成功的回调函数，当状态变成失败时再调用失败的回调函数
 *      多次调用：then可以被多次执行，我们需要将成功的回调函数和失败的回调函数存储为数组，在状态变成成功的是时候调用数组里面的函数，当状态变成失败的时候调用数组里面的回调函数 
 *      链式调用：then方法是promise下面的要实现then的链式调用， 如果then方法返回promise对象才可能实现对then方法的链式调用。
 *       后面一个then方法的回调函数拿到的值是上一个then回调函数的返回值，上一个then方法可以返回一个普通值也可以返回一个promise。
 *              1、如果上一个then返回一个普通值得时候，我们之间通过resolve方法将返回的值直接传递给下一个then方法
 *              2、如果上一个then方法返回的是一个promise对象，我们需要判断返回值得的状态是否是成功，成功的值直接通过resolve方法返回，返回值是失败直接调用rejected的方法返回
 *              3、then方法链式调用识别Promise对象自返回：当then返回它自己的promise对象时出现了promise的循环调用，我们应该抛出异常,避免程序继续往下执行
 *              4、then方法里面的参数是可选参数，如果上一个then中没有传递参数，它会在传递下一个then中的参数值
 * 4、捕获错误：当执行器报错时我们应该能够在then方法失败的回调函数中拿到错误的信息，当上一个then方法的回调函数报错时，我们在下一个then方法的失败的回调函数中捕获到对应的错误
 * 5、all方法： all方法允许我们按照异步代码调用的顺序得到异步代码执行的结果
 *              all是一个静态的方法，它里面传递一个数组，数组里面可以是普通值，也可以promise对象，
 *              数组中结构的顺序一定是得到结果的顺序，all方法也是返回的是promise对象，所以可以链式调用then方法
 *              all有一个特点，all中的所有promise对象，如果状态都是成功的，则结果都是成功的，如果有一个是失败的则结果为失败
 * 6、resolve方法：
 *              是一个静态的方法，里面可以传递一个参数，这个参数可以是普通值，也可以是promise对象
 *              作用是：将里面的参数转换成promise对象返回，所有可以链式调用then方法
 * 7、finally方法：
 *               返回的也是一个promise对象
 *               无论promise对象的 最终的状态是成功还是失败，finally 里面的回调函数都会被执行
 *               在finally方法后面我们可以链式调用then方法拿到 当前promise最终返回的结果
 *               注：在finally后面链式调用then的时候，当finally里面的回调函数返回的是一个异步操作，我们需要等待这个异步操作完成之后，才能执行后面链式调用then里面的函数
 * 8、catch方法：用来处理当前promise的最终状态是失败的情况的，里面 传递一个失败的回调函数
 * */ 
const PENDING='pending';
const FULFILLED='fulfilled'
const REJECTED='rejected'
class MyPromise{
    constructor(actuator){
        try {
            actuator(this.resolve,this.rejected)
        } catch (error) {
            this.rejected(error)
        }
        
    }
    // Promise的状态
    status=PENDING
    //存储成功之后的值
    successValue=undefined
    //存储失败后的原因
    failReason=undefined
    //存储成功的回调函数
    successCallback=[]
    //存储失败的回调函数
    failCallback=[]
    // 将状态从pending->fufilled，并将成功之后的值传递出去
    resolve=value=>{
        if(this.status!==PENDING) return
        this.status=FULFILLED
        // 保存成功之后的值
        this.successValue=value
        while(this.successCallback.length) this.successCallback.shift()()
        // this.successCallback&&this.successCallback(this.successValue)
    }
     // 将状态从pending->rejected，并将失败之后的原因传递出去
    rejected=reason=>{
        if(this.status!==PENDING) return
        this.status=REJECTED
        // 保存失败之后的原因
        this.failReason=reason
        // this.faillCallback&&this.faillCallback(this.failReason)
        while(this.failCallback.length) this.failCallback.shift()()
    }
    then(successCallback,failCallback){
        successCallback=successCallback?successCallback:value=>value;
        failCallback =failCallback?failCallback:reason=>{throw reason }
        let promise2=new MyPromise((resolve,rejected)=>{
            // 如果状态为成功，调用成功的回调函数
        if(this.status===FULFILLED){
            setTimeout(()=>{
                try {
                    let x= successCallback(this.successValue)
                    // resolve(x)
                    resolvePromise(promise2,x,resolve,rejected) 
                } catch (error) {
                    rejected(error)
                }
            },0)
           
        }else if(this.status===REJECTED){
        // 如果状态失败调用失败的回调函数
            setTimeout(()=>{
                try {
                    let x= failCallback(this.failReason)
                    // resolve(x)
                    resolvePromise(promise2,x,resolve,rejected) 
                } catch (error) {
                    rejected(error)
                }
            },0)
        }else{
           //如果状态为等待，将成功回调函数和失败回调函数存储起来
            this.successCallback.push(()=>{
                setTimeout(()=>{
                    try {
                        let x= successCallback(this.successValue)
                        // resolve(x)
                        resolvePromise(promise2,x,resolve,rejected) 
                    } catch (error) {
                        rejected(error)
                    }
                },0)
            })
            this.failCallback.push(()=>{
                setTimeout(()=>{
                    try {
                        let x= failCallback(this.failReason)
                        // resolve(x)
                        resolvePromise(promise2,x,resolve,rejected) 
                    } catch (error) {
                        rejected(error)
                    }
                },0)
            })
        }
        })
        
        return promise2
    }
    finally(callback){
        return this.then(value=>{
           return MyPromise.resolve(callback()).then(()=>value)
         },reason=>{
            return MyPromise.resolve(callback()).then(()=>{throw reason })
         })
    }
    catch(failCallback){
        return this.then(undefined,failCallback)
    }
    static all(array){
        let result=[]
        let index=0;
        return new MyPromise((resolve,rejected)=>{
            function addData(key,value){
                result[key]=value;
                index++
                if(index===array.length) resolve(result)
            }
            for(let i=0;i<array.length;i++){
                if(array[i] instanceof MyPromise){
                    array[i].then(value=> addData(i,value),error=>rejected(error))
                }else{
                    addData(i,array[i])
                }
            }
           
        })
    }
    static resolve(value){
        if(value instanceof MyPromise) return value
        return new MyPromise(resolve=>resolve(value))
    }
}
function resolvePromise(promise2,x,resolve,rejected){
    // 识别Promise对象自返回
    if(promise2===x){
        return rejected(new TypeError('Chaining cycle detected for promise #<Promise>'))
    }
    //判断x的值是普通值还是promise对象
    //如果是普通值 直接调用resolve
    //如果是promise对象 查看promise对象返回的结果
    // 再根据promise对象返回的结果，决定调用resolve还是还是调用reject
    if(x instanceof MyPromise){
        // promise 对象
        // x.then(value=>resolve(value),reason=>rejected(reason))
         x.then(resolve,rejected);
    }else{
        // 普通值
        resolve(x)
    }
}
module.exports=MyPromise